﻿<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>看门狗</title>
    <script src="jquery.js"></script>
    <script src="loger.js"></script>

    <style type="text/css">
        body {
            /*height: 800px;*/
        }

        .button {
            width: 100px;
            height: 30px;
            margin-left: 0px;
            margin-right: 0px;
            margin-top: 5px;
            border: 1px solid #d1d1d1;
            /*color: #424842bb;*/
        }

            .button:hover {
                border: 2px solid #d1d1d1;
            }

        .editButton {
            width: 80px;
            height: 30px;
            margin-left: 2px;
            margin-top: 2px;
        }

        .table {
            margin-top: 5px;
        }

            .table th {
                font: bold 12px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
                /*color: #424842bb;*/
                border-right: 1px solid #d1d1d1;
                border-bottom: 1px solid #d1d1d1;
                border-top: 1px solid #d1d1d1;
                letter-spacing: 2px;
                text-transform: uppercase;
                text-align: center;
                padding: 6px 6px 6px 12px;
                background: #CAE8EA no-repeat;
            }

            .table td {
                border-right: 1px solid #d1d1d1;
                border-bottom: 1px solid #d1d1d1;
                background: #fff;
                font-size: 14px;
                padding: 6px 6px 6px 12px;
                /*color: #424842bb;*/
                table-layout: fixed;
                word-break: break-all;
            }

                .table td.alt {
                    background: #F5FAFA;
                    /*color: #797268;*/
                }

            .table th.spec, td.spec {
                border-left: 1px solid #d1d1d1;
            }

            .table tr.select th, tr.select td {
                background-color: #CAE8EA;
                /*color: #797268;*/
            }

        .divMain {
            /*width: 1300px;*/
            height: 570px;
            /*background-color: dimgray;*/
            border: 1px solid #d1d1d1;
            margin: auto;
        }

        .divEdit {
            /*width: 1300px;*/
            height: 600px;
            background-color: darkgray;
            z-index: 10;
            position: relative;
            display: none;
            /*margin: auto;
            position: relative;*/
        }

        .tblEdit {
            width: 700px;
            height: 350px;
            position: relative;
            margin: auto;
            top: 150px;
            background-color: darkgray;
        }


        .txtEdit {
            width: 530px;
            height: 25px;
            margin-left: 10px;
        }

        .checkboxEdit {
            width: 35px;
            height: 25px;
        }
    </style>

    <script type="text/javascript">
        let pluginId = "B0CC06B1-4A4C-4A20-B251-A0F08FE573D2";
        let baseUrl = null;
        let tblEle = null;
        let divEditEle = null;
        let divEditShadowEle = null;
        let logDivEle = null;

        let appArr = null;


        function showRet(ret, status) {
            if (ret.status == 1) {
                if (ret.Data) {
                    loger.info(ret.Data);
                }
                else if (ret.data) {
                    loger.info(ret.data);
                }
                else {
                    loger.info("status:" + status + "\r\n" + ret);
                }
            }
            else {
                if (ret.Data) {
                    loger.error(ret.Data);
                }
                else if (ret.data) {
                    loger.error(ret.data);
                }
                else {
                    loger.error("status:" + status + "\r\n" + ret);
                }
            }
        }

        function showErrRet(err) {
            if (err.status == 200) {
                //浏览器bug,内容复杂的json解析会失败,提示说解析错误.不鸟它
                loger.error(err.responseText);
            }
            else {
                loger.error(err.statusText);
            }
        }

        function getReqHeaders() {
            let headers =
            {
                "token": "xxx",
                "uid": 1
            };

            return headers;
        }

        function toShowyyyyMMddHHmmss(date) {
            if (!(date instanceof Date)) {
                throw "date,且不能为空或未定义";
            }

            let year = date.getFullYear();
            let month = date.getMonth() + 1;//月取值0-11，所以+1
            let days = date.getDate();
            let h = date.getHours();
            let m = date.getMinutes();
            let s = date.getSeconds();
            return year + "-" + month + "-" + days + " " + h + ":" + m + ":" + s;
        }

        function getTrId(appName) {
            return "tr_" + appName;
        }

        function getTrByAppName(appName) {
            let trId = getTrId(appName);
            return document.getElementById(trId);
        }

        function getMonitorStatusText(isMonitor) {
            if (isMonitor) {
                return "已监视";
            }
            else {
                return "未监视";
            }
        }

        function getRunStatusText(runStatus) {
            if (runStatus) {
                return "运行";
            }
            else {
                return "停止";
            }
        }

        function updateTdValue(appName, index, text) {
            let tr = getTrByAppName(appName);
            if (tr == null || tr == undefined) {
                refreshAppList();
            }
            else {
                tr.children[index].innerText = text;
            }
        }

        function getStartTimeText(startTime) {
            if (startTime == null || startTime == undefined) {
                return "";
            }
            else {
                //return toShowyyyyMMddHHmmss(startTime);
                return startTime;
            }
        }

        function getEnableHeartCheckText(enableHeartCheck, heartTimeoutSeconds) {
            if (enableHeartCheck == true) {
                return "启用/" + heartTimeoutSeconds + "s";
            }
            else {
                return "禁用";
            }
        }

        function refreshAppList() {
            let url = baseUrl + "getAppList";
            tblEle.innerHTML = "";
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: function (ret, status) {
                    if (typeof (ret) == "string") {
                        loger.info(ret);
                    }
                    else {
                        if (ret.status == 1) {
                            appArr = JSON.parse(ret.data);
                            let html = "", argsText, des;
                            for (let appItem of appArr) {
                                if (appItem.arguments == null || appItem.arguments == undefined) {
                                    argsText = "";
                                }
                                else {
                                    argsText = appItem.arguments;
                                }

                                if (appItem.des == null || appItem.des == undefined) {
                                    des = "";
                                }
                                else {
                                    des = appItem.des;
                                }

                                html += '<tr id="' + getTrId(appItem.appName) + '"> <td>' + appItem.appName + "</td>\
                                                    <td>" + argsText + "</td>\
                                                    <td>" + appItem.appExeFilePath + "</td>\
                                                    <td>" + getRunStatusText(appItem.runStatus) + "</td>\
                                                    <td>" + getMonitorStatusText(appItem.isMonitor) + "</td>\
                                                    <td>" + getStartTimeText(appItem.startTime) + "</td>\
                                                    <td>" + appItem.delayStartTime + "</td>\
                                                    <td>" + getEnableHeartCheckText(appItem.enableHeartCheck, appItem.heartTimeoutSeconds) + '</td>\
                                                    <td>' + des + '</td>\
                                                    <td>\
                                                        <button onclick="startApp(\'' + appItem.appName + '\')" class="editButton">启动</button>\
                                                        <button onclick="stopApp(\''+ appItem.appName + '\')" class="editButton">停止</button>\
                                                        <button onclick="editApp(\''+ appItem.appName + '\')" class="editButton">编辑</button>\
                                                        <button onclick="enableMonitorApp(\''+ appItem.appName + '\')" class="editButton">启用监视</button>\
                                                        <button onclick="disableMonitorApp(\''+ appItem.appName + '\')" class="editButton">停止监视</button>\
                                                        <button onclick="deleteApp(\''+ appItem.appName + '\')" class="editButton">删除</button>\
                                                    </td> </tr>';
                            }
                            tblEle.innerHTML = html;
                        }
                        else {
                            loger.error(ret.data);
                        }
                    }
                },
                error: showErrRet
            });
        }





        function websocketReceiveMessage(e) {
            let appChangedMessage = JSON.parse(e.data);
            switch (appChangedMessage.messageType) {
                case undefined:
                case null:
                    loger.warn("没有消息类型字段");
                    break;
                case 0://无效消息
                    loger.warn("无效消息");
                    break;
                case 1://运行状态改变消息(运行/停止)
                    updateTdValue(appChangedMessage.appNames[0], 3, getRunStatusText(appChangedMessage.runStatus));
                    updateTdValue(appChangedMessage.appNames[0], 4, getMonitorStatusText(appChangedMessage.isMonitor));
                    updateTdValue(appChangedMessage.appNames[0], 5, getStartTimeText(appChangedMessage.startTime));
                    break;
                case 2://监视状态改变消息(监视/未监视)
                    updateTdValue(appChangedMessage.appNames[0], 4, getMonitorStatusText(appChangedMessage.isMonitor));
                    break;
                case 3://应用修改消息(应用编辑)
                case 4://增加应用消息(添加了应用列表)
                case 5://删除应用消息(删除了应用列表)
                    refreshAppList();
                    //let tr = getTrByAppName(appName);
                    //tr.remove();
                    break;
                default:
                    break;
            }
        }

        let WORK_ADD = 0;
        let WORK_MODIFY = 1;
        let workMod = WORK_ADD;
        let websocketUrl = null;

        _websocket = null;
        function _createWebSocket() {
            _closeWebsocket();

            _websocket = new WebSocket(websocketUrl);
            _websocket.onopen = function (e) {
                loger.info('webSocket connection opened .');
                let authObj = {};
                authObj.pluginID = pluginId;
                authObj.dataType = 1;
                authObj.data = pluginId;
                let json = JSON.stringify(authObj);
                _websocket.send(json);
                loger.info('webSocket 向服务端发送插件认证消息完成.');
            };

            _websocket.onmessage = websocketReceiveMessage;
            _websocket.onclose = function (e) {
                loger.info('Connection closed.' + e.code + ' ' + e.reason);
                _createWebSocket();
            };
            _websocket.onerror = function (e) {
                //loger.error(e);
                loger.error("websocket连接服务端失败,等待3秒后重试.");
                setTimeout(_createWebSocket, 3000);
                //_createWebSocket();
            };
        }

        function _closeWebsocket() {
            let webSocket = _websocket;
            if (webSocket == null) {
                return;
            }

            _websocket = null;
            webSocket.onopen = null;
            webSocket.onmessage = null;
            webSocket.onclose = null;
            webSocket.onerror = null;
            webSocket.close();
        }

        function getHeartPort() {
            let url = baseUrl + "getHeartPort";
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: function showRet(ret, status) {
                    if (ret.status == 1) {
                        document.getElementById("tdHeartCheckPort").innerText = "udp端口:" + ret.data;
                    }
                    else {
                        if (ret.Data) {
                            loger.error(ret.Data);
                        }
                        else if (ret.data) {
                            loger.error(ret.data);
                        }
                        else {
                            loger.error("status:" + status + "\r\n" + ret);
                        }
                    }
                },
                error: showErrRet
            });
        }

        function onLoad() {
            loger.logerIns = window.parent.getLogerIns()

            tblEle = document.getElementById("tbl");
            divEditShadowEle = document.getElementById("divEditShadow");
            divEditEle = document.getElementById("divEdit");
            logDivEle = document.getElementById("divRet");
            enableHeartCheckboxOnClick();

            baseUrl = window.document.location.origin + "/api/v1/watchdog/";
            websocketUrl = window.document.location.origin.replace("http://", "ws://");

            refreshAppList();
            _createWebSocket();
            getHeartPort();
        }

        //function choiceExePath() {
        //    let ele = document.getElementById("txtChoiceExeFile");
        //    ele.value = "";//清空前一次选择的文件
        //    ele.click();
        //}
        //function choiceExeFileChanged(sender) {
        //    let files = sender.files;
        //    if (files.length < 1) {
        //        return;
        //    }

        //    let url = window.URL.createObjectURL(files[0]);
        //    //注:获取不到物理路径,只能手动输入物理路径了
        //}

        function showEdit() {
            divEditShadowEle.style.display = 'block';
            divEditEle.style.display = 'block';
        }

        function hidenEdit() {
            divEditShadowEle.style.display = 'none';
            divEditEle.style.display = 'none';
        }

        function addApp() {
            document.getElementById("txtName").value = "";
            document.getElementById("txtExePath").value = "";
            document.getElementById("txtStartArgs").value = "";
            document.getElementById("txtDelayStartSeconds").value = "0";
            document.getElementById("txtDes").value = "";

            //document.getElementById("txtName").value = "getcolor";
            //document.getElementById("txtExePath").value = "D:\\Soft\\getcolor.exe";
            //document.getElementById("txtStartArgs").value = "";
            //document.getElementById("txtDelayStartSeconds").value = "0";
            //document.getElementById("txtDes").value = "AAAAABBBBB0101";

            showEdit();
            workMod = WORK_ADD;
        }

        function allAppStart() {
            let url = baseUrl + "startAll";
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        function allAppStop() {
            let url = baseUrl + "closeAll";
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        function allAppRestart() {
            let url = baseUrl + "restartAll";
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }



        function startApp(appName) {
            let url = baseUrl + "startApp?appName=" + appName;
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        function stopApp(appName) {
            let url = baseUrl + "closeApp?appName=" + appName;
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        let modifyAppItem = null;
        function editApp(appName) {
            modifyAppItem = null;
            for (let appItem of appArr) {
                if (appItem.appName == appName) {
                    modifyAppItem = appItem;
                    break;
                }
            }

            if (modifyAppItem == null) {
                loger.error('应用"' + appName + '"不存在,忽略操作');
                refreshAppList();
                return;
            }

            document.getElementById("txtName").value = modifyAppItem.appName;
            document.getElementById("txtExePath").value = modifyAppItem.appExeFilePath;
            document.getElementById("txtStartArgs").value = modifyAppItem.arguments;
            document.getElementById("txtDelayStartSeconds").value = modifyAppItem.delayStartTime;
            document.getElementById("txtEnableHeartCheck").checked = editAppItem.enableHeartCheck;
            document.getElementById("txtDes").value = modifyAppItem.des;

            divEditShadowEle.style.display = 'block';
            divEditEle.style.display = 'block';
            workMod = WORK_MODIFY;
        }

        function enableMonitorApp(appName) {
            let url = baseUrl + "enableMonitorApp?appName=" + appName;
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        function disableMonitorApp(appName) {
            let url = baseUrl + "disableMonitorApp?appName=" + appName;
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        function deleteApp(appName) {
            let url = baseUrl + "removeApp?appName=" + appName;
            $.ajax({
                type: "GET",
                url: url,
                async: true,
                headers: getReqHeaders(),
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                success: showRet,
                error: showErrRet
            });
        }

        function enableHeartCheckboxOnClick() {
            if (document.getElementById("txtEnableHeartCheck").checked == true) {
                document.getElementById("txtHeartTimeoutSeconds").disabled = false;
            }
            else {
                document.getElementById("txtHeartTimeoutSeconds").disabled = true;
            }
        }

        function editOk() {
            let editAppItem = {};
            let url;
            if (workMod == WORK_ADD) {
                url = baseUrl + "addApp";
                editAppItem.oldAppName = "";
            }
            else if (workMod == WORK_MODIFY) {
                url = baseUrl + "modifyApp";
                editAppItem.oldAppName = modifyAppItem.appName;
            }
            else {
                loger.info("未实现的工作模式值:" + workMod);
                return;
            }

            editAppItem.appName = document.getElementById("txtName").value.trim();
            editAppItem.appExeFilePath = document.getElementById("txtExePath").value.trim();
            editAppItem.arguments = document.getElementById("txtStartArgs").value.trim();
            editAppItem.delayStartTime = parseInt(document.getElementById("txtDelayStartSeconds").value);
            editAppItem.enableHeartCheck = document.getElementById("txtEnableHeartCheck").checked;
            editAppItem.heartTimeoutSeconds = parseInt(document.getElementById("txtHeartTimeoutSeconds").value);
            editAppItem.des = document.getElementById("txtDes").value.trim();

            if (editAppItem.appName == null ||
                editAppItem.appName == undefined ||
                editAppItem.appName.length == 0) {
                loger.warn("应用程序名称不能为空");
                return;
            }

            if (editAppItem.appExeFilePath == null ||
                editAppItem.appExeFilePath == undefined ||
                editAppItem.appExeFilePath.length == 0) {
                loger.warn("应用程序路径不能为空");
                return;
            }

            if (Number.isNaN(editAppItem.appName)) {
                loger.warn("延迟启动时间值无效");
                return;
            }

            if (editAppItem.enableHeartCheck == true && Number.isNaN(editAppItem.heartTimeoutSeconds)) {
                loger.warn("心跳超时时长值无效");
                return;
            }

            let json = JSON.stringify(editAppItem);
            $.ajax({
                type: "POST",
                url: url,
                data: json,
                async: true,
                contentType: "application/json; charset=utf-8",
                //dataType: "json",
                headers: getReqHeaders(),
                //success: showRet,
                success: function (ret, status) {

                    if (ret.status == 1) {
                        hidenEdit();
                    }
                    else {
                        showRet(ret, status);
                    }
                },
                error: showErrRet
            });
        }

        function cancellEdit() {
            hidenEdit();
        }

    </script>


</head>
<body onload="onLoad()">
    <div class="divMain">
        <button onclick="addApp()" style="margin-left: 5px;" class="button">添加应用</button>
        <button onclick="allAppStart()" class="button">全部启动</button>
        <button onclick="allAppStop()" class="button">全部停止</button>
        <button onclick="allAppRestart()" class="button">全部重启</button>
        <button onclick="refreshAppList()" class="button">刷新列表</button>

        <table class="table">
            <thead>
                <tr>
                    <td style="width:100px">应用名称</td>
                    <td style="width:100px">启动参数</td>
                    <td style="width:300px">启动文件路径</td>
                    <td style="width:80px">运行状态</td>
                    <td style="width:80px">监视状态</td>
                    <td style="width:110px">启动时间</td>
                    <td style="width:110px">延迟启动时间(s)</td>
                    <td style="width:100px">心跳检测/间隔</td>
                    <td style="width:130px">备注</td>
                    <td style="width:290px">编辑</td>
                </tr>
            </thead>
            <tbody id="tbl">
                <tr>
                    <td>宽带侦察服务1</td>
                    <td></td>
                    <td>D:\SelfCode\UtilZ\UtilZ.Tools\DotnetCore\UtilZ.ParaServiceSln\UtilZ.ParaService.WebApp\wwwroot\css\site.css</td>
                    <td>运行</td>
                    <td>2022-12-13 23:24:26</td>
                    <td>15</td>
                    <td>启用</td>
                    <td>AAAAABBBBB0001</td>
                    <td>
                        <button onclick="startApp('aa')" class="editButton">启动</button>
                        <button onclick="stopApp('aa')" class="editButton">停止</button>
                        <button onclick="editApp('aa')" class="editButton">编辑</button>
                        <button onclick="enableMonitorApp('aa')" class="editButton">启用监视</button>
                        <button onclick="disableMonitorApp('aa')" class="editButton">停止监视</button>
                        <button onclick="deleteApp('aa')" class="editButton">删除</button>
                    </td>
                </tr>
                <tr>
                    <td>宽带侦察服务2</td>
                    <td></td>
                    <td>D:\SelfCode\UtilZ\UtilZ.Tools\DotnetCore\UtilZ.ParaServiceSln\UtilZ.ParaService.WebApp\wwwroot\css\site.css</td>
                    <td>运行</td>
                    <td>2022-12-13 23:24:26</td>
                    <td>禁用</td>
                    <td>15</td>
                    <td>AAAAABBBBB0001</td>
                    <td>
                        <button onclick="clearConsole()" class="editButton">启动</button>
                        <button onclick="clearConsole()" class="editButton">停止</button>
                        <button onclick="clearConsole()" class="editButton">编辑</button>
                        <button onclick="clearConsole()" class="editButton">启用监视</button>
                        <button onclick="clearConsole()" class="editButton">停止监视</button>
                        <button onclick="clearConsole()" class="editButton">删除</button>
                    </td>
                </tr>
            </tbody>
            <tfoot>

            </tfoot>
        </table>
    </div>

    <div id="divEditShadow" class="divEdit" style="opacity: 0.3;top:-600px;">

    </div>
    <div id="divEdit" class="divEdit" style="background-color: transparent; top: -1200px; ">
        <table class="tblEdit">
            <tr>
                <td align="right" style="width: 120px;">应用程序名称</td>
                <td align="left" style="width:300px;"><input id="txtName" value="" class="txtEdit" /></td>
            </tr>
            <tr>
                <td align="right">应用程序路径</td>
                <td align="left">
                    <input id="txtExePath" value="" class="txtEdit" />
                    <!--<input id="txtChoiceExeFile" type="file" name="file" value="请选择文件" style="display:none" onchange="choiceExeFileChanged(this)">
                    <button style="width:50px;height:20px;" onclick="choiceExePath()">...</button>-->
                </td>
            </tr>
            <tr>
                <td align="right">启动参数</td>
                <td align="left"><input id="txtStartArgs" value="" class="txtEdit" /></td>
            </tr>
            <tr>
                <td align="right">延迟启动时间(s)</td>
                <td align="left"><input id="txtDelayStartSeconds" value="" class="txtEdit" /></td>
            </tr>
            <tr>
                <td align="right">启用心跳机制</td>
                <td align="left">
                    <table>
                        <tr>
                            <td style="width: 185px">
                                <input id="txtEnableHeartCheck" type="checkbox" class="checkboxEdit" style="margin-left: 1px" onclick="enableHeartCheckboxOnClick()" />
                                <span id="tdHeartCheckPort" style="position:absolute; top:210px">udp端口:52010</span>
                            </td>
                            <td align="right" style="width: 120px;">心跳超时时长(s)</td>
                            <td align="left" style="width:50px;"><input id="txtHeartTimeoutSeconds" value="-1" class="txtEdit" style="width:50px" /></td>
                            <td align="left" style="width: 160px;">小于等于0使用默认值</td>
                        </tr>
                    </table>
                    <!--<span><input id="txtEnableHeartCheck" type="checkbox" class="checkboxEdit" /></span>
                    <span>心跳超时时长(s)小于0使用默认值</span>
                    <span><input id="txtHeartTimeoutSeconds" value="-1" class="txtEdit" style="width:200px"/></span>-->
                </td>
                <!--<td align="left"><input id="txtEnableHeartCheck" type="checkbox" checked="checked" class="checkboxEdit" /></td>-->
            </tr>
            <tr>
                <td align="right">备注说明</td>
                <td align="left"><input id="txtDes" value="" class="txtEdit" /></td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <button class="button" style="margin-left: 10px" onclick="editOk()">确定</button>
                    <button class="button" onclick="cancellEdit()">取消</button>
                </td>
            </tr>
        </table>
    </div>
</body>
</html>
